/*
 * Copyright 2012 Finbudget.com
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package finbudget.client.ui.widget;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.HasAllKeyHandlers;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.event.logical.shared.HasSelectionHandlers;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Focusable;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.HasEnabled;
import com.google.gwt.user.client.ui.HasText;
import com.google.gwt.user.client.ui.HasValue;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.PushButton;
import com.google.gwt.user.client.ui.SuggestBox;
import com.google.gwt.user.client.ui.ValueBoxBase;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.SuggestOracle.Suggestion;

import finbudget.client.general.NodeSuggestionOracle;
import finbudget.client.lists.ListArrivedEvent;
import finbudget.client.lists.ListArrivedHandler;
import finbudget.client.lists.GetListOfItems.ListType;

public class SuggestDropdownBox extends Composite implements Focusable, HasSelectionHandlers<Suggestion>, HasEnabled,
		HasText, HasValue<String>, HasAllKeyHandlers, ListArrivedHandler {

	private static SuggestDropdownBoxUiBinder uiBinder = GWT.create(SuggestDropdownBoxUiBinder.class);

	interface SuggestDropdownBoxUiBinder extends UiBinder<Widget, SuggestDropdownBox> {
	}
	
	@UiField HTMLPanel containerPanel;
	@UiField(provided = true) SuggestBox suggest;
	@UiField PushButton showVariantsButton;
	@UiField Label labelWatingForList;

	private final NodeSuggestionOracle oracle;
	private boolean enabled = true;
	private String initialValue;
	private ListType listType;

	public SuggestDropdownBox(NodeSuggestionOracle oracle) {
		suggest = new SuggestBox(oracle);
		this.oracle = oracle;
		initWidget(uiBinder.createAndBindUi(this));
		labelWatingForList.setVisible(false);
		initialValue = null;
	}

	public SuggestDropdownBox(NodeSuggestionOracle oracle, String initialValue) {
		suggest = new SuggestBox(oracle);
		this.oracle = oracle;
		initWidget(uiBinder.createAndBindUi(this));
		this.initialValue = null;
		labelWatingForList.setVisible(false);
		if (initialValue != null) {
			if (oracle.getListItemsQty() > 0) {
				// The list is already on the client.
				suggest.setValue(oracle.getItemNameByKey(initialValue));
				if (suggest.getValue() == null) {
					suggest.setValue(initialValue);
				}
			} else {
				// The list is not yet arrived. Wait for it.
				this.initialValue = initialValue;
				this.listType = oracle.getListType();
				labelWatingForList.setVisible(true);
				oracle.getListsManager().addListArrivedEventHandler(this);
			}
		}
	}

	@Override
	protected void onAttach() {
		super.onAttach();
		showVariantsButton.setTabIndex(-1);
	}

	@UiHandler("showVariantsButton")
	void onClick(ClickEvent e) {
		/*
		 * TODO
		 * extend DefaultSuggestionDisplay and pass to suggest box constructor.
		 * Reason: change css-styles on the fly to add scrollbar functionality
		 * when displaying hundreds of suggestions when the left button is clicked.
		 */
		oracle.setItemsAsDefaultSuggestions();
		suggest.showSuggestionList();
	}

	@Override
	public HandlerRegistration addValueChangeHandler(ValueChangeHandler<String> handler) {
		return suggest.addValueChangeHandler(handler);
	}

	@Override
	public String getValue() {
		return suggest.getValue();
	}

	@Override
	public void setValue(String value) {
		suggest.setValue(value);
	}

	@Override
	public void setValue(String value, boolean fireEvents) {
		suggest.setValue(value, fireEvents);
	}

	@Override
	public HandlerRegistration addKeyUpHandler(KeyUpHandler handler) {
		return suggest.addKeyUpHandler(handler);
	}

	@Override
	public HandlerRegistration addKeyDownHandler(KeyDownHandler handler) {
		return suggest.addKeyDownHandler(handler);
	}

	@Override
	public HandlerRegistration addKeyPressHandler(KeyPressHandler handler) {
		return suggest.addKeyPressHandler(handler);
	}

	@Override
	public String getText() {
		return suggest.getText();
	}

	@Override
	public void setText(String text) {
		suggest.setText(text);
	}

	public ValueBoxBase<String> getTextBox() {
		return suggest.getValueBox();
	}

	@Override
	public boolean isEnabled() {
		return enabled;
	}

	@Override
	public void setEnabled(boolean enabled) {
		this.enabled = enabled;
		suggest.getValueBox().setEnabled(enabled);
		showVariantsButton.setEnabled(enabled);
	}

	@Override
	public HandlerRegistration addSelectionHandler(SelectionHandler<Suggestion> handler) {
		return suggest.addSelectionHandler(handler);
	}

	@Override
	public int getTabIndex() {
		return suggest.getTabIndex();
	}

	@Override
	public void setAccessKey(char key) {
		suggest.setAccessKey(key);
	}

	@Override
	public void setFocus(boolean focused) {
		suggest.setFocus(focused);
	}

	@Override
	public void setTabIndex(int index) {
		suggest.setTabIndex(index);
	}

	public NodeSuggestionOracle getOracle() {
		return oracle;
	}

	@Override
	public void onListArrived(ListArrivedEvent event) {
		if (initialValue != null && listType != null && event != null) {
			if (listType.equals(event.getListType())) {
				String currentValue = suggest.getValue();
				if (currentValue == null || currentValue.trim().isEmpty()) {
					suggest.setValue(oracle.getItemNameByKey(initialValue));
					if (suggest.getValue() == null) {
						suggest.setValue(initialValue);
					}
				}
				initialValue = null;
				listType = null;
				labelWatingForList.setVisible(false);
				oracle.getListsManager().removeListArrivedEventHandler(this);
			}
		}
	}

	public void setWidth(int width) {
		if (width < 25) {
			width = 25;
		}
		suggest.setWidth((width - 28) + "px");
	}

	public void setHeight(int height) {
		if (height < 20) {
			height = 20;
		}
		height -= 4;	// border 2px set in stylesheet
		suggest.setHeight(height + "px");
	}
}
